require 'abstractvirtualnode'

# Implementa a interface basica definida em AbstractVirtualNode de tal forma a
# representar um no' remoto. Isso e' feito usando DRuby como mecanismo de chamada
# remotada.
class RemoteVirtualNode < AbstractVirtualNode
  attr_reader :port
  attr_accessor :host

  # Construtor.
  # * +protocol+ - String do protocolo a usar no DRuby.
  # * +host+ - Host sobre o qual esta rodando.
  # * +port+ - Porta a conectar.
  def initialize(protocol, host, port)
    @host = host
    @port = port
    begin
      @drb_object = DRbObject.new(nil, "#{protocol}://#{host}:#{port}")
      @node_id = @drb_object.node_id
    rescue DRb::DRbError => e
      raise(DRb::DRbError, "Init: ConnectionFail")
    end
  end
  
  def notify(node)
    begin
      ping
      @drb_object.notify(node)
    rescue DRb::DRbError => e
      #puts "Exception => Notify"
      raise(DRb::DRbError, "Notify: ConnectionFail")
    end
  end
 
  def join(node)
    begin
      ping
      @drb_object.join(node)
    rescue DRb::DRbError => e
      #puts "Exception => Join"
      raise(DRb::DRbError, "Join: ConnectionFail")
    end
  end
  
  def find_successor(id)
    begin
      ping
      @drb_object.find_successor(id)
    rescue DRb::DRbError => e
      raise(DRb::DRbError, "Find Successor: ConnectionFail")
    end
  end
  
  def get_succ_list
    begin
      ping
      #como o primeiro sucessor no create eh o proprio node tenho que testar se os parametros sao validos
      successors = @drb_object.get_succ_list 
      if successors[0].host == 'localhost'
        successors[0].host = @host
      end
      return successors
    rescue DRb::DRbError => e
      return []
      #puts "Exception => Get Succ List"
      raise(DRb::DRbError, "Get Succ List: ConnectionFail")
    end
  end
  
  def get_pred_list
    begin
      ping
      return @drb_object.get_pred_list
    rescue DRb::DRbError => e
      return nil
      #puts "Exception => Get Pred List"
      raise(DRb::DRbError, "Get Pred List: ConnetionFail")
    end
  end
  
  def update_succ_list(successors)
    begin
      @drb_object.update_succ_list(successors)
    rescue DRb::DRbError => e 
      raise(DRb::DRbError, "Update Succ List: ConnectionFail")
    end
  end
  
  def ping
    begin
      ok = @drb_object.ping
      return ok
    rescue DRb::DRbError => e
      #puts "DENTRO DO PING"
      #puts "#{e.class} : #{e.message}"
      return false
    end
  end
  
  def get_item(key)
    @drb_object.get_item(key)
  end
  
  def insert_item(key, value)
    @drb_object.insert_item(key, value)
  end
  
  def remove_item(key)
    @drb_object.remove_item(key)
  end
end
